/**
 * Author:江帆
 * Description: Job的增删查改
 * Date:2025-10-1
 */
package service

import (
	"fmt"
	"kubernate-server/conf"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/goccy/go-json"
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/utils/pointer"
)

type JobService struct {
}

/*
*	获取job的详情信息
 */
/*
*	获取job的详情信息
 */
func (*JobService) GetJobDetail(ctx *gin.Context) {
	// 定义返回结构体变量
	var rsp jobRsp

	// 获取路径参数
	namespace := ctx.Param("nameSpace")
	jobName := ctx.Param("jobName")
	fmt.Println("查询的Job信息：", namespace, jobName)

	// 获取Job详情
	jobDetail, err := conf.KuberConfigSet.BatchV1().Jobs(namespace).Get(ctx, jobName, metav1.GetOptions{})
	if err != nil {
		// 错误处理：返回空结构体或错误信息（根据业务需求调整）
		rsp.JobName = jobName
		rsp.NameSpace = namespace
		ctx.JSON(http.StatusInternalServerError, rsp)
		return
	}

	// 填充基本信息
	rsp.JobName = jobDetail.Name
	rsp.NameSpace = jobDetail.Namespace

	// 处理容器信息（取第一个容器）
	if len(jobDetail.Spec.Template.Spec.Containers) > 0 {
		container := jobDetail.Spec.Template.Spec.Containers[0]
		rsp.ContainerName = container.Name
		rsp.ContainerImage = container.Image

		// 拼接命令和参数为字符串
		var cmdArgs []string
		cmdArgs = append(cmdArgs, container.Command...) // 命令
		cmdArgs = append(cmdArgs, container.Args...)    // 参数
		rsp.CommandArgs = strings.Join(cmdArgs, " ")    // 用空格分隔
	}

	// 处理标签（转换为JSON字符串）
	labelsJson, err := json.Marshal(jobDetail.Labels)
	if err != nil {
		rsp.Labels = "parse labels error: " + err.Error()
	} else {
		rsp.Labels = string(labelsJson)
	}

	// 处理时间（转换为RFC3339格式字符串）
	if jobDetail.Status.StartTime != nil {
		rsp.StartTime = jobDetail.Status.StartTime.Format(time.RFC3339)
	}
	if jobDetail.Status.CompletionTime != nil {
		rsp.EndTime = jobDetail.Status.CompletionTime.Format(time.RFC3339)
	}

	// 处理关联Pod状态
	pods, err := conf.KuberConfigSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
		LabelSelector: fmt.Sprintf("job-name=%s", jobName), // 通过job-name标签关联Pod
	})
	if err != nil {
		rsp.PodsStatuses = "get pods error: " + err.Error()
	} else {
		var podStatusList []string
		for _, pod := range pods.Items {
			podStatusList = append(podStatusList,
				fmt.Sprintf("pod[%s]:%s", pod.Name, pod.Status.Phase))
		}
		rsp.PodsStatuses = strings.Join(podStatusList, "; ")
	}
	rsp.code = "20000"
	// 返回结构体
	ctx.JSON(http.StatusOK, rsp)
}

/*
*	GetJobList 获取Job列表（支持空namespace时返回所有命名空间的Job）
*	- 若传入namespace（非空）：返回该命名空间下的Job
*	- 若未传入namespace（空）：返回所有命名空间下的Job
 */
func (*JobService) GetJobList(ctx *gin.Context) {
	// 1. 获取命名空间参数（从URL路径中获取，如/namespaces/{nameSpace}/jobs）
	namespace := ctx.Param("nameSpace") // 允许为空，空则表示"所有命名空间"

	// 2. 调用K8s API获取Job列表（根据namespace是否为空决定范围）
	var jobList *batchv1.JobList
	var err error

	// 核心逻辑：空namespace时获取所有命名空间的Job，否则获取指定命名空间的Job
	// K8s客户端中，Jobs(namespace)当namespace为空时，默认返回所有命名空间的资源
	jobList, err = conf.KuberConfigSet.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{})
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"message": "获取Job列表失败",
			"error":   err.Error(),
		})
		return
	}

	// 3. 转换K8s原生Job列表为自定义响应结构体
	var rspList []jobRsp
	for _, job := range jobList.Items {
		// 提取容器信息（默认取第一个容器）
		var containerName, containerImage string
		var commandArgs []string
		if len(job.Spec.Template.Spec.Containers) > 0 {
			container := job.Spec.Template.Spec.Containers[0]
			containerName = container.Name
			containerImage = container.Image
			// 合并命令和参数（更完整的命令展示）
			commandArgs = append(commandArgs, container.Command...)
			commandArgs = append(commandArgs, container.Args...)
		}

		// 格式化Pod状态
		podStatus := fmt.Sprintf(
			"活跃: %d, 成功: %d, 失败: %d",
			job.Status.Active,
			job.Status.Succeeded,
			job.Status.Failed,
		)

		// 转换标签为字符串（保留原始格式）
		labels := fmt.Sprintf("%v", job.Labels)

		// 处理时间格式（空值保护）
		startTime := ""
		if job.Status.StartTime != nil {
			startTime = job.Status.StartTime.String()
		}
		endTime := ""
		if job.Status.CompletionTime != nil {
			endTime = job.Status.CompletionTime.String()
		}

		// 构建响应对象
		rsp := jobRsp{
			JobName:        job.Name,
			NameSpace:      job.Namespace, // 保留Job实际所属的命名空间
			ContainerName:  containerName,
			ContainerImage: containerImage,
			CommandArgs:    strings.Join(commandArgs, " "), // 命令+参数拼接为字符串
			Labels:         labels,
			StartTime:      startTime,
			EndTime:        endTime,
			PodsStatuses:   podStatus,
		}

		rspList = append(rspList, rsp)
	}

	// 4. 返回响应（包含总数和列表）
	ctx.JSON(http.StatusOK, gin.H{
		"code":    20000,
		"message": "success",
		"count":   len(rspList), // 实际返回的Job总数（所有或指定命名空间）
		"jobList": rspList,      // 转换后的Job列表
	})
}

/*
*	添加一个job
 */
/*
*	添加一个job
 */
func (*JobService) CreateJob(ctx *gin.Context) {
	// 调用转换函数生成K8s Job对象
	k8sJob := creatJobReq2K8s(ctx)
	if k8sJob == nil {
		// 转换失败已在creatJobReq2K8s中返回错误，此处直接返回
		return
	}

	// 调用K8s API创建Job
	_, err := conf.KuberConfigSet.BatchV1().Jobs(k8sJob.Namespace).Create(
		ctx,
		k8sJob,
		metav1.CreateOptions{},
	)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"message": "创建Job失败",
			"error":   err.Error(),
		})
		return
	}

	// 构建返回结果（使用jobRsp结构体）
	/*
			rsp := jobRsp{
			JobName:        createdJob.Name,
			NameSpace:      createdJob.Namespace,
			ContainerName:  createdJob.Spec.Template.Spec.Containers[0].Name,
			ContainerImage: createdJob.Spec.Template.Spec.Containers[0].Image,
			CommandArgs:    strings.Join(createdJob.Spec.Template.Spec.Containers[0].Command, " "),
			Labels:         fmt.Sprintf("%v", createdJob.Labels), // 转换标签为字符串
			StartTime:      createdJob.Status.StartTime.String(),
			EndTime:        createdJob.Status.CompletionTime.String(),
			// endTime和PodsStatuses需Job运行后才有值，此处可能为空
		}
	*/

	ctx.JSON(http.StatusOK, gin.H{
		"code":    20000,
		"message": "success",
	})
}

// 定义创建job的请求体（字段改为大写开头，允许JSON绑定）
type jobReq struct {
	JobName        string `json:"jobName"`   // 首字母大写，导出字段
	NameSpace      string `json:"nameSpace"` // 与JSON标签对应
	ContainerName  string `json:"containerName"`
	ContainerImage string `json:"containerImage"`
	Command        string `json:"command"` // 容器命令（字符串，如"python3 -c print('hello')"）
}

// 定义job创建成功后返回的job信息
type jobRsp struct {
	code           string `json:"code"`
	JobName        string `json:"jobName"`
	NameSpace      string `json:"nameSpace"`
	ContainerName  string `json:"containerName"`
	ContainerImage string `json:"containerImage"`
	CommandArgs    string `json:"commandArgs"` // 命令参数拼接成字符串
	Labels         string `json:"labels"`
	StartTime      string `json:"start_time"`
	EndTime        string `json:"end_time"`
	PodsStatuses   string `json:"podsStatuses"`
}

// 转换请求体到K8s Job对象
func creatJobReq2K8s(ctx *gin.Context) *batchv1.Job {
	var req jobReq

	// 绑定JSON请求体到req（仅需调用一次）
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"message": "请求参数格式错误",
			"error":   err.Error(),
		})
		return nil
	}

	// 打印调试信息
	fmt.Printf("JobName: %s\n", req.JobName)
	fmt.Printf("NameSpace: %s\n", req.NameSpace)
	fmt.Printf("ContainerName: %s\n", req.ContainerName)
	fmt.Printf("ContainerImage: %s\n", req.ContainerImage)
	fmt.Printf("Command: %s\n", req.Command)

	// 将命令字符串按空格拆分为切片（处理任意数量空格）
	commandSlice := strings.Fields(req.Command)
	if len(commandSlice) == 0 {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"message": "命令参数不能为空",
		})
		return nil
	}

	// 构建K8s Job对象
	return &batchv1.Job{
		ObjectMeta: metav1.ObjectMeta{
			Name:      req.JobName,   // 从请求体获取，而非URL参数
			Namespace: req.NameSpace, // 从请求体获取
		},
		Spec: batchv1.JobSpec{
			BackoffLimit: pointer.Int32Ptr(3), // 失败重试3次（默认值）
			Template: corev1.PodTemplateSpec{
				Spec: corev1.PodSpec{
					RestartPolicy: corev1.RestartPolicyNever,
					Containers: []corev1.Container{
						{
							Name:    req.ContainerName,
							Image:   req.ContainerImage,
							Command: commandSlice, // 使用拆分后的命令切片
						},
					},
				},
			},
		},
	}
}

/*
*	删除Job
 */
func (*JobService) DeleteJob(ctx *gin.Context) {
	var err = conf.KuberConfigSet.BatchV1().Jobs(ctx.Param("nameSpace")).Delete(ctx, ctx.Param("jobName"), metav1.DeleteOptions{})
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{
			"message": fmt.Sprintf("获取Job失败: %v", err),
		})
		return
	}
	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"messge": "failure",
		})
		return
	}
	ctx.JSON(http.StatusOK, gin.H{
		"code":   20000,
		"messge": "success",
	})
}
